﻿
Imports System.Reflection

Partial Public Class autoJob(Of hash_t, impl_t As autoJob(Of hash_t, impl_t))
    Protected Class field
        Public Delegate Function required_d(ByVal i As impl_t) As Boolean
        Public Delegate Sub init_d(ByVal i As impl_t)
        Public Delegate Function respond_d(ByVal i As impl_t) As Boolean
        Public Delegate Function valid_d(ByVal i As impl_t, ByVal j As Int64) As Boolean
        Public Shared ReadOnly fields() As FieldInfo = Nothing
        Public Shared ReadOnly types() As Type = Nothing
        Public Shared ReadOnly serializers() As serializer_d = Nothing
        Public Shared ReadOnly deserializers() As deserializer_d = Nothing
        Public Shared ReadOnly required() As required_d = Nothing
        Public Shared ReadOnly valid() As valid_d = Nothing
        Public Shared ReadOnly init() As init_d = Nothing
        Public Shared ReadOnly respond() As respond_d = Nothing

        Shared Sub New()
            Const bf As BindingFlags = BindingFlags.NonPublic Or BindingFlags.Static
            fields = impl_type.GetFields(BindingFlags.Instance Or BindingFlags.Public)
            assert(fields.Length() > 0)
            ReDim types(fields.Length() - 1)
            ReDim required(fields.Length() - 1)
            ReDim valid(fields.Length() - 1)
            ReDim init(fields.Length() - 1)
            ReDim respond(fields.Length() - 1)
            For i As Int64 = 0 To fields.Length() - 1
                types(i) = find_bytes_type(fields(i).FieldType())
                If types(i) Is Nothing Then
                    types(i) = fields(i).FieldType()
                    serializers(i) = Function(x) convertor.cast(Of toBytes)(x)
                    deserializers(i) = Function(x) convertor.cast(Of Object)(x)
                Else
                    serializers(i) = find_serializer(fields(i).FieldType())
                    deserializers(i) = find_deserializer(types(i))
                End If
                required(i) = +New invoker(Of required_d)(impl_type, bf, strcat(fields(i).Name(), "_required"))
                init(i) = +New invoker(Of init_d)(impl_type, bf, strcat(fields(i).Name(), "_init"))
                Do
                    Dim j As Int64 = 0
                    j = i
                    Dim try_invoker As _do(Of String, Boolean) =
                        Function(ByRef s As String) As Boolean
                            Dim iv As invoker(Of valid_d) = Nothing
                            iv = New invoker(Of valid_d)(impl_type, bf, strtolower(strcat(s, "_valid")))
                            Return iv.valid() AndAlso eva(valid(j), +iv)
                        End Function
                    If Not try_invoker(fields(i).Name()) AndAlso
                       Not try_invoker(fields(i).FieldType().Name()) Then
                        valid(i) = Function(impl As impl_t, field_id As Int64) As Boolean
                                       Return True
                                   End Function
                    End If
                Loop Until True
                respond(i) = +New invoker(Of respond_d)(impl_type, bf, strcat(fields(i).Name(), "_respond"))
            Next

            For i As Int64 = 0 To types.Length() - 1
                Dim j As Object = Nothing
                j = Global.alloc(types(i))
                assert(Not j Is Nothing)
                assert(istype(Of equalBytes)(j))
                assert(Not serializers(i) Is Nothing)
            Next
        End Sub
    End Class

    'default as not required
    Protected Overridable Function required(ByVal i As Int64) As Boolean
        assert(i >= 0 AndAlso i < field.required.Length())
        Return Not field.required(i) Is Nothing AndAlso field.required(i)(Me)
    End Function

    'default as respond
    Protected Overridable Function respond(ByVal i As Int64) As Boolean
        assert(i >= 0 AndAlso i < field.respond.Length())
        Return field.respond(i) Is Nothing OrElse field.respond(i)(Me)
    End Function

    Private Overloads Function valid(ByVal i As Int64) As Boolean
        assert(i >= 0 AndAlso i < field.valid.Length())
        assert(Not field.valid(i) Is Nothing)
        Return field.valid(i)(Me, get_value(i))
    End Function

    Private Sub init(ByVal i As Int64)
        assert(i >= 0 AndAlso i < field.init.Length())
        If Not field.init(i) Is Nothing Then
            field.init(i)(Me)
        End If
    End Sub

    Private Sub set_value(ByVal i As Int64, ByVal v As Object)
        assert(i >= 0 AndAlso i < field.fields.Length())
        field.fields(i).SetValue(Me, v)
    End Sub

    Private Function get_value(ByVal i As Int64) As Object
        assert(i >= 0 AndAlso i < field.fields.Length())
        Return field.fields(i).GetValue(Me)
    End Function
End Class
